#include "Log.hpp"
#include "Socket.hpp"
#include<sys/select.h>

#define MAX_FD_NUM 1024
class SelectServer
{
    const static int DefaultFD = -1;

public:
    SelectServer(uint16_t port) : _port(port), _listensockfd(std::make_unique<TcpSocket>())
    {
        _listensockfd->BuildListenSocket(port);
    }

    void Init()
    {
        int pos = 1;
        for (int i=1; i < MAX_FD_NUM; i++)
        {
            arr_fd[i]=DefaultFD;
        }
        arr_fd[pos] = _listensockfd->Sockfd();
    }
    void Acceptor()
    {
        struct sockaddr_in addr;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        socklen_t len;
        int sock = ::accept(_listensockfd->Sockfd(), (struct sockaddr *)&addr, &len);
        if (sock < 0)
        {
            LOG(ERROR, "accept failed!\n");
            return;
        }
        int pos = 1;
        for (; pos < MAX_FD_NUM; pos++)
        {
            if (arr_fd[pos] == DefaultFD)
                break;
        }
        if (pos == MAX_FD_NUM)
        {
            LOG(ERROR, "select 监控位置已满 ! \n");
            return;
        }
        arr_fd[pos] = sock;
    }
    void HandlerIO(int pos)
    {
        char buffer[4096];
        ssize_t n = ::recv(arr_fd[pos], buffer, sizeof(buffer)-1,0);
        if (n == 0)
        {
            LOG(DEBUG, "write close!\n");
            arr_fd[pos] = DefaultFD;
        }
        if (n == -1)
        {
            LOG(ERROR, "read error!\n");
            arr_fd[pos] = DefaultFD;
        }
        else
        {
            buffer[n] = 0;
            std::cout << "Client say# " << buffer << std::endl;
            std::string content = "<html><body><h1>hello Linux</h1></body></html>";
            std::string echo_str = "HTTP/1.0 200 OK\r\n";
            echo_str += "Content-Type: text/html\r\n";
            echo_str += "Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";
            echo_str += content;
            send(arr_fd[pos], echo_str.c_str(), echo_str.size(),0);
        }
    }
    void HandleEvent(fd_set &rfds)
    {

        for (int i = 0; i < MAX_FD_NUM; i++)
        {
            if (!FD_ISSET(arr_fd[i], &rfds))
                continue;
            if (arr_fd[i] == _listensockfd->Sockfd())
            {
                Acceptor();
            }
            else
            {
                HandlerIO(i);
            }
        }
    }
    void Loop()
    {
        LOG(INFO, "开始循环\n");
        while (1)
        {
            fd_set rfds;
            FD_ZERO(&rfds);
            int max_fd = 0;
            for (int i = 1; i < MAX_FD_NUM; i++)
            {
                if (arr_fd[i] == DefaultFD)
                    continue;
                FD_SET(arr_fd[i], &rfds);

                if (max_fd < arr_fd[i])
                    max_fd = arr_fd[i];
            }
            struct timeval timeout = {30, 0};
            int n = ::select(max_fd + 1, &rfds, nullptr, nullptr, &timeout);
            switch (n)
            {
            case 0:
                LOG(DEBUG, "time out ! %d , %d \n", timeout.tv_sec, timeout.tv_usec);
                break;
            case -1:
                LOG(ERROR, "select error !\n");
                break;
            default:
                HandleEvent(rfds); // 如果不处理，select会一直提醒
                sleep(1);
                break;
            }
        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensockfd;
    int arr_fd[MAX_FD_NUM] = {DefaultFD};
};